#include <conio.h>
#include <peekpoke.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crcmodel.h"
#include "DriveTests.h"
#include "DriveRoutines.h"
#include "globalInput.h"
#include "Screen.h"
#include "Main.h"
#include "PAL_NTSC.h"

unsigned char initialDrive;

void main(void)
{
	unsigned int i = 0;
	unsigned int result;
	bool save = false;

	initialDrive = _curunit;

	POKE(0xDC08, 0);

	bgcolor(COLOR_BLACK);
	bordercolor(COLOR_BLACK);
	clrscr();

	enumerateDrives(initialDrive);

	selectDrives();

#ifdef __C64__
	sprintf(buffer, "%s C64", checkC64PALorNTSC() ? "PAL" : "NTSC");
#else
	sprintf(buffer, TARGET);
#endif
	cputsxy(0, 2, buffer);

	waitForEnterEscf("Prepare selected drives, then hit RETURN.");

	for(i = 0; i < (drives[9].drive > 0 ? 10 : 9); ++i)
	{
		if(drives[i].isSelected)
		{
			benchmarkDrive(i);
			displayResults(i);
			save = true;
		}
	}

	if(save && (waitForEnterEscf("Hit RETURN to save, ESC to exit.") != CH_STOP)) 
	{
		saveResults();
	}
}

unsigned int crcROM()
{
	unsigned long i;
	unsigned int crc;
	cm_t my_cm_t;
	p_cm_t p_cm = &my_cm_t;

	p_cm->cm_width = 16;
	p_cm->cm_poly  = 0x8005L;
	p_cm->cm_init  = 0L;
	p_cm->cm_refin = TRUE;
	p_cm->cm_refot = TRUE;
	p_cm->cm_xorot = 0L;  

	writeStatusBar("Preparing CRC of KERNAL ROM.");

	cm_ini(p_cm);

	for(i = 0x031a; i <= 0x033B; ++i)
	{
		writeStatusBarf("Calculating %04X", (unsigned int)i);
		cm_nxt(p_cm, PEEK(i));
	}

	for(i = 0xe000; i <= 0xfffful; ++i)
	{
		writeStatusBarf("Calculating %04X", (unsigned int)i);
		cm_nxt(p_cm, PEEK(i));
	}

	writeStatusBarf("Getting CRC.");
	crc = cm_crc(p_cm);

	writeStatusBarf("CRC is %04X", crc);

	return crc;
}

void saveResults()
{
	unsigned char r = 0, i = 0, j = 0;
	static char message[41];
	
	sprintf(message, "@0:results.%s,s,w", TARGET);
	writeStatusBarf("Saving: %s", message);
	r = cbmOpen(3, initialDrive, 3, message, 15);

	if(r == 0)
	{
		sprintf(message, "%s\n", VERSION);
		cbm_write(3, message, strlen(message));

#ifdef __C64__
		sprintf(message, "%s %s,%u\n\n", (checkC64PALorNTSC() ? "pal": "ntsc"), TARGET, crcROM());
#else
		sprintf(message, "%s,%u\n\n", TARGET, crcROM());
#endif
		cbm_write(3, message, strlen(message));

		for(i = 0; i < (drives[9].drive > 0 ? 10 : 9); ++i)
		{
			if(drives[i].isSelected)
			{
				sprintf(message, "%02d %s\n", drives[i].drive, drives[i].message + 3);
				cbm_write(3, message, strlen(message));

				for(j = 0; j < 13; ++j)
				{
					sprintf(message, "%02d, %4u, %llu.%u, %s\n", j, 
							drives[i].driveScores[j]->score, 
							drives[i].driveScores[j]->elapsedTime->Time / 1000ul, 
							drives[i].driveScores[j]->elapsedTime->Milisecond,
							tests[j]);

					cbm_write(3, message, strlen(message));
				}

				cbm_write(3, "----------------------\n\n", 
					strlen(  "----------------------\n\n"));
			}
		}
	}
	else
	{
		writeStatusBarf(buffer);
	}

	cbm_close(3);
	cbm_close(15);

	clrscr();
}

void displayResults(const unsigned char driveIndex)
{
	char stringBuffer[41];
	
	clrscr();

	sprintf(stringBuffer, "%02d %s", drives[driveIndex].drive, drives[driveIndex].message + 3);
	cputsxy(0, 1, drives[driveIndex].message);

	sprintf(stringBuffer, "Test            CBMMarks  El. Time");
	cputsxy(0, 3, stringBuffer);

	cputsxy(0, 4,         "------------    --------  --------");

	sprintf(stringBuffer, "PRG WRITE 4K  : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_WRITE_4K]->score, drives[driveIndex].driveScores[PRG_WRITE_4K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_WRITE_4K]->elapsedTime->Milisecond);
	cputsxy(0, 5, stringBuffer);

	sprintf(stringBuffer, "PRG READ 4K   : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_READ_4K]->score, drives[driveIndex].driveScores[PRG_READ_4K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_READ_4K]->elapsedTime->Milisecond);
	cputsxy(0, 6, stringBuffer);

	sprintf(stringBuffer, "PRG WRITE 8K  : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_WRITE_8K]->score, drives[driveIndex].driveScores[PRG_WRITE_8K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_WRITE_8K]->elapsedTime->Milisecond);
	cputsxy(0, 7, stringBuffer);

	sprintf(stringBuffer, "PRG READ 8K   : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_READ_8K]->score, drives[driveIndex].driveScores[PRG_READ_8K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_READ_8K]->elapsedTime->Milisecond);
	cputsxy(0, 8, stringBuffer);

	//sprintf(stringBuffer, "PRG WRITE 12K : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_WRITE_12K]->score, drives[driveIndex].driveScores[PRG_WRITE_12K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_WRITE_12K]->elapsedTime->Milisecond);
	//cputsxy(0, 9, stringBuffer);

	//sprintf(stringBuffer, "PRG READ 12K  : %4u      %llu.%u", drives[driveIndex].driveScores[PRG_READ_12K]->score, drives[driveIndex].driveScores[PRG_READ_12K]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[PRG_READ_12K]->elapsedTime->Milisecond);
	//cputsxy(0, 10, stringBuffer);

	sprintf(stringBuffer, "SEQ WRITE 400 : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_WRITE_400]->score, drives[driveIndex].driveScores[SEQ_WRITE_400]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_WRITE_400]->elapsedTime->Milisecond);
	cputsxy(0, 11, stringBuffer);

	sprintf(stringBuffer, "SEQ READ 400  : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_READ_400]->score, drives[driveIndex].driveScores[SEQ_READ_400]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_READ_400]->elapsedTime->Milisecond);
	cputsxy(0, 12, stringBuffer);

	sprintf(stringBuffer, "SEQ WRITE 40  : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_WRITE_40]->score, drives[driveIndex].driveScores[SEQ_WRITE_40]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_WRITE_40]->elapsedTime->Milisecond);
	cputsxy(0, 13, stringBuffer);

	sprintf(stringBuffer, "SEQ READ 40   : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_READ_40]->score, drives[driveIndex].driveScores[SEQ_READ_40]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_READ_40]->elapsedTime->Milisecond);
	cputsxy(0, 14, stringBuffer);

	sprintf(stringBuffer, "SEQ WRITE 4   : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_WRITE_4]->score, drives[driveIndex].driveScores[SEQ_WRITE_4]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_WRITE_4]->elapsedTime->Milisecond);
	cputsxy(0, 15, stringBuffer);

	sprintf(stringBuffer, "SEQ READ 4    : %4u      %llu.%u", drives[driveIndex].driveScores[SEQ_READ_4]->score, drives[driveIndex].driveScores[SEQ_READ_4]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[SEQ_READ_4]->elapsedTime->Milisecond);
	cputsxy(0, 16, stringBuffer);

	sprintf(stringBuffer, "REL WRITE     : %4u      %llu.%u", drives[driveIndex].driveScores[REL_WRITE]->score, drives[driveIndex].driveScores[REL_WRITE]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[REL_WRITE]->elapsedTime->Milisecond);
	cputsxy(0, 17, stringBuffer);

	sprintf(stringBuffer, "REL READ      : %4u      %llu.%u", drives[driveIndex].driveScores[REL_READ]->score, drives[driveIndex].driveScores[REL_READ]->elapsedTime->Time / 1000ul, drives[driveIndex].driveScores[REL_READ]->elapsedTime->Milisecond);
	cputsxy(0, 18, stringBuffer);

}